home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
DDJ0992.ARJ
/
DBCMD.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-07-03
|
79KB
|
1,743 lines
;dbcmd.asm
;Debugger command processing routines
;
.386P
;----------------------------------------------------------------------------
;Copyright 1991, 1992 ASMicro Co.
;7/6/91 Rick Knoblaugh
;-----------------------------------------------------------------------------
include dbequ.inc
include dbstruc.inc
include dbdat.inc
zcode segment para public 'code16' use16
extrn ck_exec_bp:near, scroll_cmds_up:near, skip_white_sp:near
extrn convert_upper:near, prt_err_msg:near, get_validate:near
extrn clear_buffer:near, must_be_hex:near, editor:near
extrn put_hex_byte:near, put_nibble:near, format_seg:near
extrn do_left:near, do_right:near, do_rub_out:near
extrn do_insert:near, do_delete:near, put_hex_word:near
extrn xudflag:byte, xud_ip:word, xud_cs:word, xud_int:byte
extrn convert_2_linear:near
public do_the_cmd, set_trap, show_regs, reset_trap
public do_bpint
assume cs:zcode, ds:data, es:nothing
;----------------------------------------------------------------------
; do_the_cmd - parse command strings and dispatch to appropriate |
; command processing routines. |
; |
; Enter: si = offset of start of cmd |
; cx = max chars entered - any leading white space |
; |
; Exit: carry flag set if we are to stay in debugger. |
; |
;----------------------------------------------------------------------
do_the_cmd proc near
call scroll_cmds_up
push cx
call convert_upper
mov bx, offset cmd_table
mov ax, size cmd_info
mov cx, CMD_TABLE_LEN
call str_lookup
or cx, cx ;entire table searched?
pop cx ;restore count chars
jnz short do_the_c200 ;if command found
mov si, offset syntax_msg
call prt_err_msg ;print msg and set carry
ret
do_the_c200:
;subtract cmd length from total characters entered
sub cl, [bx].cmd_len
call [bx].cmd_routine ;perform cmd processing
do_the_c999:
ret
do_the_cmd endp
;----------------------------------------------------------------------
; str_lookup - Perform table lookup for a text string. |
; |
; Enter: si = offset of string on which to match |
; ax = amount by which to increment table index |
; May be called for use with tables where |
; first two elements are: offset of text |
; and text length. Other elements may or |
; may not be present after these two. |
; |
; bx = offset of lookup table |
; cx = number of items in table |
; |
; Exit: |
; cx = zero if a match not found |
; bx = offset of record in table where found |
; si = just after end of string |
; |
; es, di, dx saved |
;----------------------------------------------------------------------
str_lookup proc near
push dx
push di
push es
push ds
pop es
mov dx, si ;save start of string
str_look100:
push cx ;count of table items
mov di, [bx].cmd_text ;get offset of string
movzx cx, [bx].cmd_len
repe cmpsb
pop cx
jz short str_look400
str_look300:
add bx, ax ;inc by record size
mov si, dx ;get back start of string
loop str_look100
str_look400:
pop es
pop di
pop dx
ret
str_lookup endp
;----------------------------------------------------------------------
; do_trace - process trace command. Valid syntax is T [n]. |
; |
; Enter: si = offset of cmd buffer just after "T" |
; cx = max chars entered - cmd length |
; |
; Exit: if command was valid, trap flag is set in flags |
; on user stack. Carry clear indicating leave |
; debugger cmd loop and ret to user code. |
; |
; trace_count = number of times to trace |
; |
; if count specified was invalid, error message |
; is displayed and return with Carry set. |
; |
;----------------------------------------------------------------------
do_trace proc near
mov ax, 1 ;default to 1 trace
call skip_white_sp
jcxz do_t100
mov dx, 4 ;get a max of 4 digits
call get_validate ;return value in ax
jc short do_t050 ;if count invalid
or ax, ax
jnz short do_t100 ;it can't be zero
do_t050:
mov si, offset bad_trace_msg
call prt_err_msg ;print msg and set carry
ret
do_t100:
mov trace_count, ax
;Save address of instruction through which we will be tracing. If it is a
;software interrupt instruction, the PL0 code will use this address to
;determine that it should generate an int 1 as the first instruction of the
;ISR is entered (i.e. this facilitates stepping through the int).
mov ax, [bp].regs_ip
mov tuser_ip, ax
mov ax, [bp].regs_cs
mov tuser_cs, ax
call set_trap
clc ;exit debugger
do_t999:
ret
do_trace endp
set_trap proc near
bts [bp].regs_f, trapf ;set trap flag
ret
set_trap endp
reset_trap proc near
btr [bp].regs_f, trapf ;reset trap flag
ret
reset_trap endp
do_go proc near
call skip_white_sp
jcxz do_g900 ;just go, so go
call get_seg_off ;go get go address
jnc short do_g100
mov si, offset bad_addrs_msg
call prt_err_msg ;print msg and set carry
ret
do_g100:
cmp seg_found, TRUE ;user specify a segment?
je short do_g200
mov dx, [bp].regs_cs ;get user cs register
do_g200:
;have go address in dx:bx
call convert_2_linear ;dx:bx to linear in edx
mov ch, 1 ;set debug register
mov al, DEB_DAT_LEN1 ;exec breaks use 1 byte length
mov ah, DEB_TYPE_EXEC
sub cl, cl ;debug reg zero for go use
cli
;
;Get PL0 code to manipulate debug registers
;
int 60h ;do_debug_reg
do_g900:
clc ;leave debugger
do_g999:
ret
do_go endp
;----------------------------------------------------------------------
; do_reg - process register command. |
; |
; Enter: si = offset of cmd buffer just after "R" |
; cx = max chars entered - cmd length |
; |
; Exit: carry set indicating go prompt for next command. |
; |
;----------------------------------------------------------------------
do_reg proc near
call skip_white_sp
or cx, cx
jnz short do_r040 ;if more than 'r' entered
;user simply entered 'r' (and nothing else)
call show_regs
stc
ret
do_r040:
;
;do processing for individual registers
;
push cx ;save number of chars entered
mov cx, REGS_TABLE_ENTRIES ;number of registers
mov bx, offset regs_info_start ;start of register info
mov ax, size regs_stab ;size to inc when search
call str_lookup
or cx, cx ;found in table?
pop cx
jnz short do_r050
mov si, offset bad_reg_msg
call prt_err_msg ;print msg and set carry
ret
do_r050:
mov si, [bx].regs_stack_off ;offset on stack for reg
push si ;save register offset
mov ax, [bp + si] ;get register value
do_r100:
movzx cx, [bx].regs_text_len
mov si, [bx].regs_text_off
push si ;save offset description
push cx ;and length
call disp_reg_eq ;display reg description
cmp [bx].regs_text_len, 1 ;was entry found flags?
jne short do_r200 ;if not, go do regular reg
call disp_reg_flags
jmp short do_r300
do_r200:
call disp_reg_val ;display reg value
do_r300:
call scroll_cmds_up ;scroll a line
pop cx
pop si
call disp_reg_eq ;display reg description
call clear_buffer
mov si, offset cmd_buffer
cmp [bx].regs_text_len, 1 ;doing flags reg?
jne short do_r350 ;if not, go do regular reg
call accept_flags ;get flags values
pop si ;restore stack offset
jnc short do_r700 ;go assign new flags
ret ;if error or user escaped
do_r350:
mov dx, 4 ;max in dl, dh=zero
xor bx, bx ;char counter
mov get_out, bx ;no "get out" key
mov ax, offset must_be_hex
mov edit_routine, ax ;assign to ptr
call editor
pop bx ;restore stack offset(was si)
movzx cx, dh ;max chars entered
call scroll_cmds_up
jcxz do_r999 ;user simply pressed return
cmp al, ESC_KEY ;user aborted?
je short do_r999
call convert_upper
mov dx, 4 ;get max of 4 digits
;get_validate returns the binary value of data (it also validates which has
;already been done, but several other places in the debugger use it for
;both functions)
call get_validate ;return value in ax
mov si, bx ;stack offset
do_r700:
mov [bp + si], ax ;put back on stack
do_r999:
stc
ret
do_reg endp
;----------------------------------------------------------------------
; accept_flags - user has been prompted to enter new flags register |
; values. Now, get those values and set/reset the |
; appropriate flags bits. If values are invalid, |
; display an error message. |
; |
; Enter: si = start of data buffer |
; es:di = destination in video buffer |
; ax = flags register value |
; |
; Exit: carry set if user presses esc or data invalid. |
; ax = updated flags register value |
;----------------------------------------------------------------------
accept_flags proc near
mov dx, CMD_MAX_LEN ;max in dl, dh=zero
xor bx, bx ;char counter
mov get_out, bx ;no "get out" key
mov edit_routine, bx ;no special edit
push ax ;save flags reg value
call editor
call scroll_cmds_up
cmp al, ESC_KEY
pop ax ;restore flags reg value
je short accept_f900
movzx cx, dh ;max chars entered
jcxz accept_f800 ;end of input (if any)
call convert_upper
accept_f100:
call skip_white_sp
jcxz accept_f800 ;end of input (if any)
push cx ;save number of chars entered
mov cx, FLAGS_TABLE_ENTRIES ;number of possibilities
mov bx, offset flags_info_start
push ax ;save flags value
mov ax, size flags_tbl ;size to inc when search
call str_lookup
pop ax ;restore flags value
or cx, cx ;found in table?
pop cx
jnz short accept_f200
mov si, offset bad_flags_msg
call prt_err_msg ;print msg and set carry
ret
accept_f200:
sub cl, [bx].flen ;subtract length of flag text
mov dl, [bx].fbit ;get bit number
sub dh, dh
bts ax, dx ;set flags bit
;
;Below, determine if user had entered the abbreviation for a cleared
;flag (e.g. user entered "NC"). If so, clear the bit
cmp bx, flags_info_mid
jb short accept_f100
btr ax, dx ;clear flags bit
jmp short accept_f100
accept_f800:
clc
ret
accept_f900:
stc
ret
accept_flags endp
show_regs proc near
xor dx, dx ;register counter
mov si, offset regs_indx
show_r100:
push si ;entry in table of indices
xor bh, bh
mov bl, [si] ;offset of register to display
cmp dx, NUM_REGS_DISP - 1
je short show_r205
;
;get start of text string for register
mov si, [bx + regs_info_start].regs_text_off
sub ch, ch
mov cl, [bx + regs_info_start].regs_text_len
show_r200:
call disp_reg_eq
show_r205:
;
;get offset on stack where register is located
mov si, [bx + regs_info_start].regs_stack_off
mov ax, [bp + si] ;get register value
cmp dx, NUM_REGS_DISP - 1 ;are we on flags?
jne short show_r250 ;if not, go do regular reg
;
;Display flags register values
;
call disp_reg_flags
jmp short show_r330
show_r250:
call disp_reg_val
show_r330:
pop si
inc si ;advance to next register
inc dx ;count one we just did
cmp dx, NUM_REGS_1LINE
jne short show_r400
call scroll_cmds_up
show_r400:
cmp dx, NUM_REGS_DISP
jb short show_r100
call scroll_cmds_up
ret
show_regs endp
;----------------------------------------------------------------------
;disp_reg_flags - display textual descriptions of flags |
; register values. |
; |
; Enter: ax = flags register contents |
; es:di = destination in video buffer |
; Exit: di adjusted |
; bx, dx saved |
;----------------------------------------------------------------------
disp_reg_flags proc near
push bx
push dx
mov bx, offset flags_info_start
mov cx, FLAGS_ALL_BITS
disp_rf210:
mov dl, [bx].fbit ;bit number in flags reg
mov si, [bx].ftext_off ;offset of bit description
push cx
sub ch, ch
mov cl, [bx].flen ;length of description
disp_rf215:
sub dh, dh
bt ax, dx ;is bit set in flags?
jc short disp_rf220 ;if so, go move text
;else advance to text for bits not set
add si, SET_FLAGS_LEN
disp_rf220:
movsb ;move desription to display
inc di ;skip attribute byte
loop disp_rf220
pop cx
add di, 2 ;next display position
add bx, size flags_tbl
loop disp_rf210
pop dx
pop bx
ret
disp_reg_flags endp
;--------------------------------------------------------------
;disp_reg_eq - display textual description of register and |
; follow it with an equals sign. |
; |
; Enter: ds:si = description text. |
; cx = length of description |
; es:di = destination in video buffer |
; Exit: di, si, cx adjusted |
; |
; ax saved |
;--------------------------------------------------------------
disp_reg_eq proc near
push ax
disp_re100:
movsb ;move text to display
inc di ;past video attribute
loop disp_re100
mov al, '=' ;equal sign
stosb
inc di
pop ax
ret
disp_reg_eq endp
;--------------------------------------------------------------
;disp_reg_val - display register value and follow it with |
; a couple of spaces. |
; |
; Enter: ax = register value |
; es:di = destination in video buffer |
; Exit: di adjusted |
; |
; DX Saved. |
;--------------------------------------------------------------
disp_reg_val proc near
push dx
call put_hex_word
pop dx
mov al, ' '
mov cx, 2 ;skip 2 spaces after register
disp_reg_v100:
stosb
inc di
loop disp_reg_v100
ret
disp_reg_val endp
do_dump proc near
mov dx, BYTES_TO_DUMP ;load default number of bytes
call skip_white_sp
or cx, cx
jnz short do_d150
do_d100:
;
;only 'd' with nothing else. If dumped before, start with last dump
;address else use ds:0
cmp did_dump, TRUE ;have dumped before?
je short do_d800
do_d150:
push dx ;save default bytes to dump
mov dx, [bp].regs_ds ;default to ds:0 for dump
mov dump_address.d_seg, dx ;store seg
xor bx, bx ;zero offset
mov dump_address.d_offset, bx ;store offset
pop dx ;restore bytes to dump
jcxz do_d800 ;if only d and no previous d
do_d200:
assume ds:data
call get_seg_off ;get seg:off in dx:bx
jnc short do_d300 ;if not invalid
do_d280:
mov si, offset bad_addrs_msg
do_d285:
call prt_err_msg ;print msg and set carry
ret
do_d300:
cmp seg_found, TRUE ;segment found?
jne short do_d350
mov dump_address.d_seg, dx ;store it
do_d350:
mov dump_address.d_offset, bx ;store offset
do_d500: ;look for range
mov dx, BYTES_TO_DUMP ;default # bytes to dump
call skip_white_sp
jcxz do_d800
mov dx, 4 ;inspect a max of 4 digits
call get_validate ;go get one
mov si, offset bad_range_msg
jc short do_d285 ;if it was invalid, exit
mov dx, 10h ;if illegal range, do 10h
cmp dump_address.d_offset, ax ;must be > offset
ja short do_d800
mov dx, ax ;"to" portion of range
sub dx, dump_address.d_offset ;minus offset
do_d800:
push ds ;save our data segment
lds si, dump_address ;get starting address
assume ds:nothing
;ready to dump
call dump_n_count
pop ds
assume ds:data
mov did_dump, TRUE ;indicate did dump
add dump_address.d_offset, dx ;pick up here next dump
do_d999:
stc ;stay in debug cmd loop
ret
do_dump endp
do_edit_b proc near
mov edit_length, 1 ;edit bytes
mov edit_num, 16 ;16 of them
call do_edit
ret
do_edit_b endp
do_edit proc near
call skip_white_sp
jcxz short do_e280
mov dx, [bp].regs_ds ;default to ds for edit seg
push dx
call get_seg_off ;get seg:off in dx:bx
pop ax ;restore default segment
jnc short do_e300 ;if not invalid
do_e280:
mov si, offset bad_addrs_msg
jmp short do_e380
do_e300:
cmp seg_found, TRUE ;segment found?
je short do_e350
mov dx, ax ;if not, use ds
do_e350:
call skip_white_sp
jcxz do_e400
mov si, offset syntax_msg
do_e380:
call prt_err_msg ;print msg and set carry
ret
do_e400:
mov edit_address.d_seg, dx
mov gs, dx ;save seg here too
mov edit_address.d_offset, bx ;save edit address
do_e425:
push ds ;save our data segment
lds si, edit_address
assume ds:nothing
call dump_a_line ;display the data
pop ds
assume ds:data
mov dl, edit_length ;length of each item to edit
movzx cx, edit_num ;number of them
mov si, offset cmd_buffer
call get_dump ;get formatted data to buffer
mov get_out, SPACE_KEY ;exit on this and cr and esc
mov ax, offset must_be_hex
mov edit_routine, ax ;editing routine for hex
;
;ds:si=edit buffer, es:di=start of edit area in video
;dl=max number of nibbles to get
do_e450:
xor bx, bx ;init char counter
mov dh, dl ;init max gone = number to get
push di ;save starting cursor position
call editor
pop di ;restore start cursor position
sub dh, dh
add di, dx ;advance past chars
add di, dx ;and attributes
add di, 2 ;past space between
push ax ;save get out key
push cx ;save number of edit items
movzx cx, dl ;max digits to get
xor ax, ax ;default to zero
call skip_white_sp
jcxz do_e490
call convert_upper
call get_validate
do_e490:
pop cx
inc si
mov bx, edit_address.d_offset
cmp edit_length, 1 ;editing bytes?
jne short do_e500
mov gs:[bx], al
jmp short do_e600
do_e500:
mov gs:[bx], ax
inc bx
do_e600:
inc bx
mov edit_address.d_offset, bx ;save edit offset
pop ax ;get out key
cmp al, ESC_KEY
je short do_e700
loop do_e450
call scroll_cmds_up
jmp short do_e425
do_e700:
call scroll_cmds_up
do_e999:
stc ;stay in debug cmd loop
ret
do_edit endp
;--------------------------------------------------------------
;get_dump - Get data ready for editing. Data has been |
; formatted and placed in the video buffer in the |
; dump format. Get the formatted data and move it |
; into the edit work buffer. Also, position the |
; pointers to the start of the data for display and |
; editing. |
; |
; Enter: |
; si = offset edit work buffer. |
; dl = length of data items in bytes |
; cx = number of data items |
; |
; |
; Exit: dl = length of data items in nibbles|
; di = offset of start of dump data |
; (past seg:offset) |
; |
; cx, si saved |
;--------------------------------------------------------------
get_dump proc near
push cx
push si
mov di, wrk_vid_offset ;get prompt location
add di, 24 ;get past prompt and "xxxx:xxxx "
push di ;save this spot
shl dl, 1 ;get number of digits
get_d100:
xor bl, bl
get_d200:
mov al, es:[di] ;get formatted data from video buf
mov [si],al ;move into work buffer
add di, 2 ;next data in video buffer
inc si ;next work buffer position
inc bl
cmp bl, dl
jne short get_d200
mov byte ptr [si], ' ' ;space between data items
inc si
add di, 2
loop get_d100
pop di
pop si
pop cx
ret
get_dump endp
;--------------------------------------------------------------
;get_seg_off - Search cmd buffer for seg:off specified as |
; registers or hex or both. |
; |
; Enter: si = offset of cmd buffer |
; cx = remaining chars in buffer |
; bp = base of stack area where user |
; regs have been stored. |
; |
; Exit: si and cx adjusted |
; gs = segment specified (if any) |
; dx = segment specified (if any) |
; seg_found = TRUE if segment specified |
; bx = offset |
; |
; carry set if invalid address |
; |
; No registers saved |
;--------------------------------------------------------------
get_seg_off proc near
mov seg_found, FALSE ;no segment found yet
push cx ;save number of chars entered
mov cx, REGS_SEGS_ENTRIES ;number of seg registers
mov bx, regs_info_segs ;start of seg register info
mov ax, size regs_stab ;size to inc when search
call str_lookup
or cx, cx
pop cx
jz short get_s300 ;if no seg register found
sub cl, [bx].regs_text_len ;subtract length of reg text
push si ;save cmd line offset
mov si, [bx].regs_stack_off ;offset on stack for reg
mov ax, [bp + si] ;get register value
mov gs, ax ;store it
mov seg_found, TRUE ;indicate we found it
pop si
call skip_white_sp
xor bx, bx ;default to zero offset
jcxz get_s800 ;if no more chars on cmd line
get_s100: ;look for ':'
cmp byte ptr [si], ':'
je short get_s290
get_s200:
stc
jmp get_s999
get_s290:
inc si ;past the ":"
call skip_white_sp
jcxz get_s200 ;if ':' was last thing
get_s300:
;look for registers used to specify offset for dump
push cx ;save number of chars entered
mov cx, REGS_GEN_ENTRIES ;number of nonseg registers
mov bx, offset regs_info_start ;start of register info
mov ax, size regs_stab ;size to inc when search
call str_lookup
or cx, cx
pop cx
jz short get_s400 ;if no registers found
sub cl, [bx].regs_text_len ;subtract length of reg text
push si
;check for sp or bp
cmp bx, offset regs_info_sp ;sp register?
je short get_s350
cmp bx, offset regs_info_bp ;bp register?
jne short get_s380
get_s350: ;if sp or bp
cmp seg_found, TRUE ;and no segment specified
je short get_s380
mov ax, [bp].regs_ss ;use stack segment
mov gs, ax ;store it
mov seg_found, TRUE ;seg "found" (bp, sp use ss)
get_s380:
mov si, [bx].regs_stack_off ;offset on stack for reg
mov bx, [bp + si] ;get register value
pop si
jmp short get_s800 ;and exit
get_s400: ;look for hex number
mov dx, 4 ;inspect a max of 4 digits
cmp seg_found, TRUE ;segment specified yet?
je short get_s425
mov dh, ':' ;may hit before 4 digits
get_s425:
call get_validate ;go get one
jc short get_s999 ;if invalid, exit with carry
cmp seg_found, TRUE ;segment specified yet?
je short get_s450
call skip_white_sp ;anthing else?
jcxz get_s450 ;if not, it was just offset
;look for ':'
cmp byte ptr [si], ':'
jne short get_s450
mov gs, ax ;store it
mov seg_found, TRUE ;segment found
jmp short get_s290 ;go look for offset
get_s450:
mov bx, ax ;return offset in bx
get_s800:
mov dx, gs ;and segment in dx
clc
get_s999:
ret
get_seg_off endp
do_quit proc near
clc ;indicate exit debugger
ret
do_quit endp
;--------------------------------------------------------------
; do_xud- Process eXit to User Debugger commmand. Look for |
; int number. If specified, validate it. If not |
; specified, use int specified in last XUD command. |
; If command was never previously issued and no int |
; is specified, use DEF_UD_INT. |
; |
; Enter: si = offset of cmd buffer just after "XUD" |
; cx = max chars entered - cmd length |
; |
; Exit: If invalid Carry set |
; else Carry clear indicating exit debugger |
; and |
; cs:xudflag=TRUE |
; cs:xud_ip=Offset of ISR for user debug int|
; cs:xud_cs=segment of same |
; cs:xud_int=int specifed |
;--------------------------------------------------------------
do_xud proc near
call skip_white_sp
jcxz do_xud090 ;no int number specified
mov dx, 2 ;get max of 2 digits, dh=0
call get_validate ;return value in ax
jnc short do_xud070
do_xud050:
mov si, offset bad_int_msg
call prt_err_msg ;print msg and set carry
ret
do_xud070:
mov bx, ax ;get specified int number
mov cs:xud_int, al ;save it for next time
jmp short do_xud500
do_xud090:
sub bh, bh
mov bl, cs:xud_int
or bl, bl ;xud done before?
jnz short do_xud500 ;if so, use last int specified
;and go get cs:ip of isr again (it may have changed)
;
mov bx, DEF_UD_INT ;else use default
do_xud500:
push ds
xor ax, ax
mov ds, ax
shl bx, 2 ;get vector entry
mov ax, [bx].d_offset
mov cs:xud_ip, ax
mov ax, [bx].d_seg
mov cs:xud_cs, ax
pop ds
do_xud900:
mov xudflag, TRUE ;indicate process XUD
clc ;indicate exit debugger
do_xud999:
ret
do_xud endp
do_bc proc near
call skip_white_sp
jcxz short do_bc900 ;error, no arguments
mov al, [si] ;get first byte of arg
cmp al, '*' ;clear all break points?
jne short do_bc100
cmp num_used, 0 ;any to clear?
je short do_bc999 ;if not, ignore command
call clear_all_bp
jmp short do_bc999
do_bc100:
mov dx, 2 ;get max of 2 digits, dh=0
call get_validate ;return value in ax
jc short do_bc900
call skip_white_sp
or cx, cx ;any remaining chars in arg?
jnz short do_bc900 ;if so, they don't belong
movzx dx, max_goneto
mov si, offset bad_bc_msg2 ;number exceeded max msg
cmp ax, dx ;is number > max
jae short do_bc950 ;if so, error
call clear_bp
jmp short do_bc999
do_bc900:
mov si, offset bad_bc_msg1
do_bc950:
call prt_err_msg
do_bc999:
stc ;stay in debug
ret
do_bc endp
clear_all_bp proc near
sub al, al ;start with first break point
clear_all100:
call clear_bp
inc al ;advance to next break point
cmp al, max_goneto
jne short clear_all100
ret
clear_all_bp endp
;--------------------------------------------------------------
;clear_bp - Clear break point. Clear the break point in the |
; master break point list. Also, clear it in the |
; detailed list (i.e. individual lists for break |
; point register type, interrupt type, or I/O type |
; break points). Decrement the counters for the |
; total number of break points and individual |
; number for the break point type. |
; |
; Enter: al = break point number to be |
; cleared. It is guaranteed to |
; be a valid existing break |
; point. |
; |
; AX saved. |
;--------------------------------------------------------------
clear_bp proc near
push ax
mov bx, offset brk_list ;get start of master list
mov dl, size mast_list
mul dl ;break point * entry size
add bx, ax ;gives offset into master list
cmp [bx].brk_type, AVAIL ;if already clear
je short clear_bp999
dec num_used ;number total breakpoints - 1
cmp [bx].brk_type, DEB_TYPE_INT ;type being cleared int?
ja short clear_bp200 ;if i/o type break point
je short clear_bp100 ;if int type break point
dec num_reg_type ;debug reg type breaks - 1
;
;Break point being cleared is a debug register type. If it is a data
;access type break point (vs execution type), decrement count of data
;type break points. Also, if this is the last debug register data access
;break point, clear the ge bit in the debug control register.
;
push bx
mov bx, [bx].brk_off ;get offset of detailed list
cmp [bx].info_bptype, DEB_TYPE_EXEC ;exec type ?
pop bx
je short clear_bp300
dec num_reg_data ;dec # data byte break points
jnz short clear_bp300
;
;Clear ge bit when last data access type break point is removed.
;
mov cx, 1 ;indicate clear/reg 1
mov ax, ge_bit ;clear ge bit
int 60h ;do_debug_reg
jmp short clear_bp300
clear_bp100:
dec num_int_bp ;int type breaks - 1
jmp short clear_bp300
clear_bp200:
dec num_io_bp ;io type breaks - 1
clear_bp300:
mov [bx].brk_type, AVAIL ;make available in master list
mov bx, [bx].brk_off ;get offset of detailed list
;
;Status is first byte in each entry in all lists.
;
mov byte ptr [bx], AVAIL ;make available in detailed lists
clear_bp999:
pop ax
ret
clear_bp endp
;--------------------------------------------------------------
; do_bl - Break point list command. Search break point |
; master list and display all active break points. |
; |
; Enter: max_goneto = highest break point number |
; that has ever been defined.|
; |
; |
;--------------------------------------------------------------
do_bl proc near
sub al, al
mov bx, offset brk_list
do_bl100:
cmp [bx].brk_type, AVAIL ;is break point active
je short do_bl510 ;if not, go get next one
push ax
push bx
call put_nibble ;display number in al
mov al, ')' ;followed by ') '
stosb
add di, 3 ;attribute, space, attribute
cmp [bx].brk_type, DEB_TYPE_INT ;what type of break point?
ja short do_bl350 ;above is I/O type
je short do_bl300 ;int type
call disp_deb_reg ;debug reg type
jmp short do_bl400
do_bl300:
call disp_int_bp
jmp short do_bl400
do_bl350:
call disp_io_bp
do_bl400:
call scroll_cmds_up
do_bl500:
pop bx
pop ax
do_bl510:
add bx, size mast_list
inc al
cmp al, max_goneto
jb short do_bl100
stc ;stay in debugger
ret
do_bl endp
disp_int_bp proc near
mov si, offset brk_pint
mov cx, BRK_PINT_LEN
disp_int100:
movsb
inc di ;past attribute
loop disp_int100
add di, 2 ;skip a space
mov bx, [bx].brk_off ;offset of int list entry
mov al, [bx].int_num ;get int number
call put_hex_byte ;display it
add di, 2 ;skip a space
;
;See if ax was specified as a condition
;
mov al, [bx].int_reg ;none, al, ah, or ax
or al, al ;none?
jz disp_int999 ;if so, done
mov cx, REGS16_TEXT_LEN
mov si, offset ax_text
cmp al, INT_AH_COMP
ja short disp_int500
mov si, offset ah_text
je short disp_int500
mov si, offset al_text
disp_int500:
pushf ;save flags per compare on reg type
disp_int510:
movsb ;put out register name
inc di ;past attribute
loop disp_int510
mov al, '='
stosb
inc di ;past attribute
mov ax, [bx].int_val
popf
ja short disp_int600 ;if ax
call put_hex_byte
jmp short disp_int999
disp_int600:
call put_hex_word
disp_int999:
ret
disp_int_bp endp
disp_io_bp proc near
mov si, offset brk_pio
mov cx, BRK_PIO_LEN
disp_io100:
movsb
inc di ;past attribute
loop disp_io100
add di, 2 ;skip a space
mov bx, [bx].brk_off ;offset of int list entry
mov ax, [bx].io_port ;get port value
call put_hex_word ;display it
add di, 2 ;skip a space
mov al, [bx].io_dir ;get indicator of port direction
mov bx, offset dir_indic_r ;decriptions and indicators
mov cx, DIR_TABLE_ENTRIES
disp_io200:
cmp [bx].text_code, al ;find entry for it?
je short disp_io400 ;if so, go get text
add bx, size off_len_code
loop disp_io200
disp_io400:
mov si, [bx].text_off ;get description of port direction
movzx cx, [bx].text_len
disp_io500:
movsb ;display it
inc di ;past attribute
loop disp_io500
disp_io999:
ret
disp_io_bp endp
disp_deb_reg proc near
mov bx, [bx].brk_off ;offset of detailed debug info
mov si, [bx].info_bpcmd ;offset of data for this cmd
movzx cx, [si].cmd_len
mov si, [si].cmd_text
disp_deb100:
movsb
inc di ;past attribute
loop disp_deb100
add di, 2 ;skip a space
push ds
lds si, dword ptr [bx].info_bpoff ;get address
call format_seg ;go display it
add di, 2 ;skip a space
pop ds
;
;Next, if break point is for data accesses, print a description of
;the type of access (i.e. "W" or "RW")
;
mov si, offset write_text ;default to write
mov cx, WRITE_LEN
mov dl, [bx].info_bptype
cmp dl, DEB_TYPE_WRITE
jb short disp_deb900 ;if execution type, no direction
je short disp_deb500
mov si, offset rw_text ;r/w description
mov cx, RW_LEN
disp_deb500:
movsb
inc di
loop disp_deb500
disp_deb900:
ret
disp_deb_reg endp
do_bp proc near
mov al, DEB_DAT_LEN1
call do_data_brk
ret
do_bp endp
do_bpw proc near
mov al, DEB_DAT_LEN2
call do_data_brk
ret
do_bpw endp
do_bpd proc near
mov al, DEB_DAT_LEN4
call do_data_brk
ret
do_bpd endp
do_bpx proc near
mov fs, bx ;save offset where command found
call skip_white_sp
jcxz do_bpx050 ;must specify address
call get_seg_off ;go get bpx address
jnc short do_bpx100
do_bpx050:
mov si, offset bad_addrs_msg
call prt_err_msg ;print msg and set carry
ret
do_bpx100:
cmp seg_found, TRUE ;user specify a segment?
je short do_bpx200
mov dx, [bp].regs_cs ;get user cs register
do_bpx200:
call check_max_deb
jc short do_bpx999
call check_max_bps
jc short do_bpx999
;have bpx address in dx:bx
push di
mov cx, MAX_BRK_POINTS ;number in list
mov ax, size mast_list
mov si, offset brk_list
call get_and_mark ;find spot in master list
;si=offset of entry in master list
mov di, si ;save in di
mov si, offset bp_reg_dat ;debug registers list
mov ax, size info_bpreg ;size of entries in list
mov cx, MAX_DR_BRK_POINTS ;number in list
call get_and_mark ;find spot and assign
;exec breaks use 1 byte length
mov ax, ( (DEB_TYPE_EXEC shl 8) OR DEB_DAT_LEN1 )
call add_to_master ;add to master list
call add_db_list
pop di
inc cl ;debug reg # = entry # + 1
call convert_2_linear ;dx:bx to linear in edx
mov ch, 2 ;setup debug register
int 60h ;do_debug_reg
do_bpx999:
stc ;stay in debug cmd loop
ret
do_bpx endp
;--------------------------------------------------------------
; do_data_brk - Process BP, BPB, BPW and BPD commands. |
; Validate command parameters. If invalid, |
; print error message else load appropriate |
; data structures and debug register. |
; |
; Enter: al = length code for debug register |
; bx = offset in command table where the |
; command (i.e. "BP", "BPB", "BPW", |
; or "BPD" was found). |
; |
; Exit: carry set. |
; |
;--------------------------------------------------------------
do_data_brk proc near
mov fs, bx ;save offset where command found
call skip_white_sp
jcxz do_data_b050 ;must specify address
push ax ;save length code
call get_seg_off ;go get break point address
pop ax ;restore length code
jnc short do_data_b100
do_data_b050:
mov si, offset bad_addrs_msg
do_data_b070:
call prt_err_msg ;print msg and set carry
ret
do_data_b100:
cmp seg_found, TRUE ;user specify a segment?
je short do_data_b200
mov dx, [bp].regs_ds ;get user ds register
do_data_b200:
;have bp address in dx:bx
mov ah, DEB_TYPE_RW ;default to r/w
call skip_white_sp
jcxz do_data_b300
push bx
push ax
mov cx, RW_W_ENTRIES ;number of ("rw", "w")
mov bx, offset dir_indic_rw ;table of text
mov ax, size off_len_code ;size to inc when search
call str_lookup
pop ax
mov ah, [bx].text_code ;get type code
pop bx
or cx, cx
jnz short do_data_b300 ;if user input was valid
;
;was expecting "W" or "RW" and didn't get either
;
mov si, offset bad_bp_msg
jmp short do_data_b070
do_data_b300:
call check_max_deb
jc short do_data_b1000
call check_max_bps
jc short do_data_b1000
push di
push ax ;save type and length
mov cx, MAX_BRK_POINTS ;number in list
mov ax, size mast_list
mov si, offset brk_list
call get_and_mark ;find spot in master list
;si=offset of entry in master list
mov di, si ;put it in di
mov si, offset bp_reg_dat ;debug registers list
mov ax, size info_bpreg ;size of entries in list
mov cx, MAX_DR_BRK_POINTS ;number in list
call get_and_mark ;find spot and assign
pop ax ;restore type and length
call add_to_master ;add to master list
call add_db_list
inc num_reg_data ;# data type break points
pop di
inc cl ;debug reg # = entry # + 1
call convert_2_linear ;dx:bx to linear in edx
mov ch, 2 ;setup debug register
int 60h ;do_debug_reg
do_data_b999:
stc ;stay in debug cmd loop
do_data_b1000:
ret
do_data_brk endp
;--------------------------------------------------------------
; get_and_mark - Find first available entry in list of break |
; points. Mark the entry as active. All |
; structures processed with this routine must |
; have the status field at the same offset. |
; |
; There will always be an available entry |
; found as callers check this first. |
; |
; This is currently called when processing the |
; lists of: debug register type break points, |
; int break points, and I/O break points. It |
; is also used to find available entries in |
; the master break point list. |
; |
; |
; Enter: si = offset of break point list |
; ax = amount by which to increment table|
; index. |
; cx = number of items in table |
; |
; Exit: si = offset where first available |
; entry found. |
; |
; cx = entry number where found. |
; |
; DX saved. |
; |
;--------------------------------------------------------------
get_and_mark proc near
push dx
mov dx, cx ;save number of entries
get_and_m100:
cmp [si].info_bpstat, AVAIL
je short get_and_m200
add si, ax ;increment to next entry
loop get_and_m100
get_and_m200:
mov [si].info_bpstat, ACTIVE ;flag as being used
sub dx, cx ;compute entry number
mov cx, dx
pop dx
ret
get_and_mark endp
;--------------------------------------------------------------
; add_db_list - Fill in an entry in the list of debug register|
; type break points. Also, flag the status as |
; "temporarily disabled" so that the break point|
; will be enabled in the debug register when |
; debugger is exited. |
; |
; Enter: si = offset for this entry in list of |
; debug register type break points. |
; al = length (0=byte, 1=word, 3=dword) |
; ah = type (0=exec, 1=write, 3=r/w) |
; dx:bx = address for break point |
; |
; fs = offset of entry in command table |
; where command was found. This |
; is stored so that a description |
; of the command can be easily |
; produced when listing break |
; points via the "BL" command. |
; |
; |
;--------------------------------------------------------------
add_db_list proc near
or [si].info_bpstat, DEB_TEMP_DISAB
mov [si].info_bpoff, bx
mov [si].info_bpseg, dx
mov [si].info_bpsize, al
mov [si].info_bptype, ah
mov [si].info_bpcmd, fs
ret
add_db_list endp
;--------------------------------------------------------------
; add_int_list - Fill in an entry in the list of interrupt |
; type break points. Also, add to num_int_bp. |
; |
; Enter: si = offset for this entry in list of |
; interrupt type break points. |
; |
; dh = interrupt number |
; |
; dl = indication of type of compare on |
; ax (0=no compare, 1=compare on al,|
; 2=compare on ah, 3=compare on |
; ax) |
; |
; ax = compare value |
; |
; Exit: num_int_bp is incremented. |
; |
;--------------------------------------------------------------
add_int_list proc near
mov [si].int_stat, ACTIVE
mov [si].int_num, dh
mov [si].int_reg, dl
mov [si].int_val, ax
inc num_int_bp ;inc int break point count
ret
add_int_list endp
;--------------------------------------------------------------
; add_io_list - Fill in an entry in the list of I/O |
; type break points. Also, add to num_io_bp. |
; |
; Enter: si = offset for this entry in list of |
; I/O type break points. |
; |
; dx = I/O port address |
; |
; al = code indicating "R", "RW" or "W" |
; |
; Exit: num_io_bp is incremented. |
; |
;--------------------------------------------------------------
add_io_list proc near
mov [si].io_port, dx
mov [si].io_dir, al
inc num_io_bp ;inc I/O break point count
ret
add_io_list endp
;--------------------------------------------------------------
; add_to_master - Fill in an entry in master list of all |
; break points. Also, advance count of |
; maximum break points ever defined in this |
; session if necessary. |
; |
; Enter: di = offset for this entry in master |
; list of break points. |
; ah = type of break point being assigned|
; to this entry (0=exec, 1=write |
; 2=unused, 3=r/w, 4=int, 5=i/o) |
; si = offset of entry in list of |
; information regarding the |
; type of break point (the entry |
; in the table of debug register |
; type break points, int type and |
; I/O type) |
; |
; ax saved |
;--------------------------------------------------------------
add_to_master proc near
push ax
mov [di].brk_type, ah ;type of break point
mov [di].brk_off, si ;entry in break table
mov al, num_used ;number of active breaks
;Compare with maximum break points ever defined in this session. (i.e. more
;may have existed before this, but user may have cleared them). This is
;maintained because when break points are cleared, the list is not
;compressed (e.g. if you have 3 break points and delete the 2nd one, you
;will still reference your active break points as #1 and #3).
;
cmp al, max_goneto
jbe short add_to_m999
inc max_goneto
add_to_m999:
pop ax
ret
add_to_master endp
do_bpio proc near
call skip_white_sp
jcxz do_bpio050 ;must specify i/o port
mov dx, 4 ;get a max of 4 digits
call get_validate ;return value in ax
jnc short do_bpio100 ;if port valid, continue
do_bpio050:
mov si, offset bad_io_msg
do_bpio070:
call prt_err_msg ;print msg and set carry
ret
do_bpio100:
mov dx, ax ;hold port address
mov al, DEB_TYPE_RW ;default to r/w
call skip_white_sp
jcxz do_bpio300
push ax
mov cx, DIR_TABLE_ENTRIES ;number of ("r", "rw", "w")
mov bx, offset dir_indic_r ;table of text
mov ax, size off_len_code ;size to inc when search
call str_lookup
pop ax
mov al, [bx].text_code ;get type code
or cx, cx
jnz short do_bpio300 ;if user input was valid
;
;was expecting "W", "RW" or "R" and didn't get any of these
;
mov si, offset bad_iodir_msg
jmp short do_bpio070
do_bpio300:
call check_max_bps
jc short do_bpio1000
push ax ;save type
mov cx, MAX_BRK_POINTS ;number in list
mov ax, size mast_list
mov si, offset brk_list
call get_and_mark ;find spot in master list
;si=offset of entry in master list
mov di, si ;put it in di
mov si, offset io_bpdat ;i/o break point list
mov ax, size info_io ;size of entries in list
mov cx, MAX_BRK_POINTS ;number in list
call get_and_mark ;find spot and assign
pop ax ;restore type
call add_io_list
mov ah, DEB_TYPE_IO ;indicate I/O type break point
call add_to_master ;add to master list
do_bpio999:
stc ;stay in debug cmd loop
do_bpio1000:
ret
do_bpio endp
do_bpint proc near
call skip_white_sp
jcxz do_bpi050 ;must specify int number
mov dx, 2 ;get max of 2 digits, dh=0
call get_validate ;return value in ax
mov dh, al ;save interrupt number in dh
jnc short do_bpi100
do_bpi050:
mov si, offset bad_int_msg
jmp short do_bpi410
do_bpi100:
mov dl, NO_CONDITION ;default to no more args
xor ax, ax ;with no compare value
call skip_white_sp
jcxz short do_bpi500
push cx ;save count chars in cmd
mov cx, AX_TABLE_ENTRIES ;3 (al, ah, and ax)
mov bx, offset tab_ax ;table of text for al, ah, ax
mov ax, size off_len_code ;size to inc when search
call str_lookup
or cx, cx
pop cx
jz short do_bpi400 ;jmp if error
;
;Found al, ah, or ax. Now, store indication of this and look for "EQ" or "="
;
call skip_white_sp
jcxz short do_bpi400
push cx
mov dl, [bx].text_code ;get al, ah, ax code
mov cx, EQ_TABLE_ENTRIES ;2 ("=" and "EQ")
mov bx, offset operators ;table of "=" and "EQ"
mov ax, size off_len_code ;size to inc when search
call str_lookup
or cx, cx
pop cx
jz short do_bpi400 ;jmp if error
call skip_white_sp
jcxz short do_bpi400
push dx ;save int number/ax code
mov al, dl
mov dx, 2 ;number of digits in byte reg
cmp al, INT_AX_COMP ;doing word reg?
jne short do_bpi200
shl dx, 1 ;number of digits in word reg
do_bpi200:
call get_validate ;return value in ax
pop dx
jnc short do_bpi500
do_bpi400:
mov si, offset syntax_msg ;error
do_bpi410:
call prt_err_msg ;print msg and set carry
ret
do_bpi500:
call check_max_bps ;see if break point > max
jc short do_bpi999 ;if so, reject it
push ax ;save compare value
push dx ;save ax type
mov cx, MAX_BRK_POINTS ;number in list
mov ax, size mast_list
mov si, offset brk_list
call get_and_mark ;find spot in master list
;si=offset of entry in master list
mov di, si ;save in di
mov si, offset int_bpdat ;int break point list
mov ax, size info_int ;size of entries in list
mov cx, MAX_BRK_POINTS ;number in list
call get_and_mark ;find spot and assign
pop dx ;restore ax type
pop ax ;and ax compare value
call add_int_list ;put info in int list
mov ah, DEB_TYPE_INT ;indicate int type break point
call add_to_master ;put into master list
do_bpi999:
stc ;stay in debug cmd loop
ret
do_bpint endp
check_max_bps proc near
cmp num_used, MAX_BRK_POINTS
jb short check_m100
mov si, offset max_bps_msg
call prt_err_msg ;print msg and set carry
ret
check_m100:
inc num_used
clc
ret
check_max_bps endp
check_max_deb proc near
;
;Logic could also be added here to prevent duplicate break points from being
;defined.
;
cmp num_reg_type, MAX_DR_BRK_POINTS
jb short check_mdb100
mov si, offset max_deb_msg
call prt_err_msg ;print msg and set carry
ret
check_mdb100:
inc num_reg_type
clc
ret
check_max_deb endp
;--------------------------------------------------------------
;dump_n_count - do a dump of specified area. |
; |
; Enter: ds:si = ptr to area. |
; dx = number of bytes. |
; Exit: dx saved. |
;--------------------------------------------------------------
dump_n_count proc near
push dx
dump_n_c100:
call dump_a_line
push ds
mov ax, DATA
mov ds, ax
call scroll_cmds_up
pop ds
cmp dx, 10h
jbe short dump_n_c200
sub dx, 10h
jmp short dump_n_c100
dump_n_c200:
pop dx
ret
dump_n_count endp
;--------------------------------------------------------------
;dump_a_line - given a ptr ds:si to a buffer, put 10h bytes |
; of dump data into video buffer at es:di. |
;--------------------------------------------------------------
dump_a_line proc near
push dx
push di ;save start print buf
call format_seg
add di,4 ;skip 2 spaces
mov cx, 10h
push si ;save start of data
dump_a_l100:
lodsb
call put_hex_byte ;print hex
cmp cl, 9
jne short dump_a_l200
mov al, '-'
mov es:[di],al
dump_a_l200:
add di, 2
loop dump_a_l100
pop si
add di, 4 ;skip 2 spaces
mov cx, 10h
dump_a_l250:
lodsb
cmp al, ' '
jae short dump_a_l300
mov al, '.'
dump_a_l300:
stosb ;print ASCII
inc di ;past attribute
loop dump_a_l250
pop di
pop dx
ret
dump_a_line endp
zcode ends
end